package mspbots.teams.client.core.data.planners;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import mspbots.teams.client.core.AbstractToolsUtil;
import mspbots.teams.client.core.BaseSyncService;
import mspbots.teams.client.oauth.TokenState;
import mspbots.teams.common.RabbitKeys;
import mspbots.teams.common.ResultMsg;
import mspbots.teams.common.ResultSync;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.time.LocalDateTime;

/**
 * mspbots.teams.client.core.data.planners.TasksServiceImpl
 *
 * @author <a href="https://github.com/vnobo">Alex bob</a>
 * @date Created by 2020/9/29
 */
@Log4j2
@Service
@RequiredArgsConstructor
public class TasksServiceImpl extends AbstractToolsUtil implements BaseSyncService {

    private final PlannersServiceImpl plannersService;

    public Flux<ObjectNode> find(Long tenantId) {
        return this.filterTasks(TokenState.withDefault(tenantId));
    }

    @Override
    public Mono<Void> syncFast(TokenState tokenState) {
        ResultSync resultSync = ResultSync.withDefault("PLANNERS-TASKS-SYNC");
        return this.filterTasks(tokenState)
                .contextWrite(ctx -> ctx.put("resultSync", resultSync))
                .doOnNext(resultNode -> this.sendEntity(RabbitKeys.PLANNER_TASKS_SYNC_QUEUE_KEY, ResultMsg.builder()
                        .requestId(resultSync.getRequestId()).id(resultNode.get("id").textValue())
                        .action("none").entity(resultNode).tenantId(tokenState.getTenantId())
                        .syncDate(LocalDateTime.now()).build()))
                .then();
    }

    private Flux<JsonNode> fetch(String planId) {
        return this.teamsClient.fetch(UriComponentsBuilder.newInstance()
                .scheme("https").host("graph.microsoft.com").path("/v1.0/planner/plans/{planId}/tasks").build(planId))
                .onErrorResume(err -> Flux.empty())
                .flatMap(jsonNode -> Flux.fromIterable(jsonNode.withArray("value")));
    }

    private Flux<ObjectNode> filterTasks(TokenState tokenState) {
        return this.plannersService.find(tokenState.getTenantId())
                .delayElements(Duration.ofSeconds(1))
                .flatMap(resultNode -> this.fetch(resultNode.get("id").textValue())
                        .map(taskNode -> {
                            ObjectNode objectNode = taskNode.deepCopy();
                            objectNode.putPOJO("plans", resultNode);
                            return objectNode;
                        }))
                .contextWrite(ctx -> ctx.put("tokenState", tokenState));
    }
}
